package com.lauor.smpedr.spring.transaction;

import com.lauor.smpedr.transaction.Transaction;
import org.springframework.jdbc.datasource.ConnectionHolder;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
 * spring 管理事务
 */
public class SpringManagedTransaction implements Transaction {

    protected Connection connection;

    protected DataSource dataSource;

    private boolean isConnectionTransactional;

    protected boolean autoCommit;

    protected boolean closed;

    public SpringManagedTransaction(DataSource dataSource) {
        Assert.notNull(dataSource, "No DataSource specified");
        this.dataSource = dataSource;
    }

    public Connection getConnection() throws SQLException {
        if (this.connection != null) return this.connection;

        this.openConnection();
        return this.connection;
    }

    protected void openConnection() throws SQLException {
        if (this.dataSource == null) return;

        this.connection = DataSourceUtils.getConnection(this.dataSource);
        if (this.connection == null) return;
        this.autoCommit = this.connection.getAutoCommit();
        this.closed = false;

        this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
    }

    public void commit() throws SQLException {
        if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
            this.connection.commit();
        }
    }

    public void rollback() throws SQLException {
        if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
            this.connection.rollback();
        }
    }

    public void close() {
        DataSourceUtils.releaseConnection(this.connection, this.dataSource);
        this.closed = true;
    }

    public Integer getTimeout() {
        ConnectionHolder holder = (ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
        if (holder != null && holder.hasTimeout()) {
            return holder.getTimeToLiveInSeconds();
        }
        return null;
    }

    @Override
    public boolean isClosed() {
        return this.closed;
    }
}
